import { 
  AmbientLight, 
  AxesHelper, 
  BoxGeometry, 
  Fog, FogExp2, 
  Mesh, MeshLambertMaterial, 
  PerspectiveCamera, PlaneGeometry, Scene, SpotLight, 
  WebGLRenderer 
} from "three"
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls'
import Stats from 'stats.js'
import dat from 'dat.gui'

const scene = new Scene()
const camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000)
const renderer = new WebGLRenderer({ antialias: true })
renderer.setClearColor(0xeeeeee)
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true

document.body.appendChild(renderer.domElement)

// 创建一个平面
const planeGeometry = new PlaneGeometry(60, 40, 10, 10)
const planeMaterial = new MeshLambertMaterial({ color: 0xffffff })
const plane = new Mesh(planeGeometry, planeMaterial)
// 接收阴影
plane.receiveShadow = true

plane.rotation.x = -0.5 * Math.PI
plane.position.x = 0
plane.position.y = 0
plane.position.z = 0

scene.add(plane)

// 添加坐标系，方便理解
const axes = new AxesHelper(15)
scene.add(axes)

// 设置相机位置
camera.position.x = -30
camera.position.y = 40
camera.position.z = 30
camera.lookAt(scene.position)

// 添加环境光
const ambientLight = new AmbientLight(0x0c0c0c)
scene.add(ambientLight)
// 添加聚光灯
const spotLight = new SpotLight(0xffffff)
spotLight.position.set(-40, 60, -10)
spotLight.castShadow = true
scene.add(spotLight)

// 添加雾
// fog(颜色， 近值，远值)
// scene.fog = new Fog(0xffffff, 0.015, 100)
// fogExp2(color, 浓度)
// scene.fog =  new FogExp2(0xffffff, 0.015)

// 材质覆盖（统一重置材质）
// scene.overrideMaterial = new MeshLambertMaterial({ color: 0xffffff })

// 添加 FPS 监控
let stats: Stats = new Stats()
stats.showPanel(0)
document.body.appendChild(stats.dom)

const controls = new function() {
  this.rotationSpeed = 0.02
  this.numberofObjects = scene.children.length
  this.cameraX = camera.position.x
  this.cameraY = camera.position.y
  this.cameraZ = camera.position.z
  
  // 添加功能
  this.addCube = function(): void {
    // 随机生成大小为 0 - 3 之间的矩形
    let cubeSize = Math.ceil(Math.random() * 3)
    let cubeGeometry = new BoxGeometry(cubeSize, cubeSize, cubeSize)
    // 随机生成颜色
    let cubeMaterial = new MeshLambertMaterial({ color: Math.random() * 0xffffff })
    let cube = new Mesh(cubeGeometry, cubeMaterial)
    cube.castShadow = true
    cube.name = 'cube-' + scene.children.length
    // 随机放置
    cube.position.x = -30 + ~~(Math.random() * planeGeometry.parameters.width)
    cube.position.y = ~~(Math.random() * 5)
    cube.position.z = -20 + ~~(Math.random() * planeGeometry.parameters.height)

    scene.add( cube )
    this.numberofObjects = scene.children.length
  }

  // 删除功能
  this.removeCube = function(): void {
    let allChildren = scene.children
    let lastObjetct = allChildren[allChildren.length -1]
    // 判断是否为网格对象，防止删除了相机与光源
    if (lastObjetct instanceof Mesh) {
      scene.remove(lastObjetct)
      // 更新元素个数
      this.numberofObjects = scene.children.length
    }
  }

  this.getCamera = function(): void {
    console.log(camera.position)
  }
}

// 控制器
const gui = new dat.GUI()
gui.add(controls, 'rotationSpeed', 0, 0.5)
gui.add(controls, 'addCube')
gui.add(controls, 'removeCube')
gui.add(controls, 'getCamera')
gui.add(controls, 'numberofObjects').listen()

// 引入轨迹球控制器，添加鼠标控制功能
const trackballControls = new TrackballControls(camera, renderer.domElement)

function render() {
  trackballControls.update()
  stats.update()

  // 每个元素动画（排除平面之后的矩形）
  scene.traverse(function(e) {
    if (e instanceof Mesh && e != plane) {
      e.rotation.x += controls.rotationSpeed
      e.rotation.y += controls.rotationSpeed
      e.rotation.z += controls.rotationSpeed
    }
  })

  requestAnimationFrame(render)
  renderer.render(scene, camera)
}
render()